import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron';
import { electronAPI } from '@electron-toolkit/preload';

// Custom APIs for renderer
type TabViewBounds = { x: number; y: number; width: number; height: number };
type KvmSessionPayload = {
  kvmIp: string;
  kvmPort: number | string;
  sessionId: string;
  webSessionId: string;
  title: string;
  token: string;
  privilege: string;
  baseUrl: string;
  csrfToken: string;
  cookieName: string;
  cookieValue: string;
  loginIp: string;
  loginPort: string;
  useCertificate?: string;
};

type IpcCallback = (...args: any[]) => void;

const registerIpcListener = (channel: string, callback: IpcCallback): (() => void) => {
  const subscription = (_event: IpcRendererEvent, ...args: any[]) => {
    callback(...args);
  };
  ipcRenderer.on(channel, subscription);
  return () => ipcRenderer.removeListener(channel, subscription);
};

const api = {
  fetchData: (params) => ipcRenderer.invoke('fetch-data', params),
  session: {
    save: (tabId: string, session: KvmSessionPayload) =>
      ipcRenderer.invoke('kvm-session-save', { tabId, session }),
    get: (tabId: string) => ipcRenderer.invoke('kvm-session-get', { tabId }),
    clear: (tabId: string) => ipcRenderer.invoke('kvm-session-clear', { tabId })
  },
  websocket: {
    connect: (connectionId: string, url: string, rejectUnauthorized?: boolean, tabId?: string) =>
      ipcRenderer.invoke('websocket-connect', { connectionId, url, rejectUnauthorized, tabId }),
    send: (connectionId: string, data: any) =>
      ipcRenderer.invoke('websocket-send', { connectionId, data }),
    disconnect: (connectionId: string) => ipcRenderer.invoke('websocket-disconnect', connectionId),
    onStatus: (callback) =>
      ipcRenderer.on('websocket-status', (_event: IpcRendererEvent, data) => callback(data)),
    onMessage: (callback) =>
      ipcRenderer.on('websocket-message', (_event: IpcRendererEvent, data) => callback(data)),
    onError: (callback) =>
      ipcRenderer.on('websocket-error', (_event: IpcRendererEvent, data) => callback(data)),
    removeAllListeners: (channel: string) => ipcRenderer.removeAllListeners(channel)
  },
  tabView: {
    create: (tabId: string, bounds: TabViewBounds, options?: { query?: Record<string, string> }) =>
      ipcRenderer.invoke('tab-view-create', { tabId, bounds, options }),
    activate: (tabId: string, bounds: TabViewBounds) =>
      ipcRenderer.invoke('tab-view-activate', { tabId, bounds }),
    resize: (tabId: string, bounds: TabViewBounds) =>
      ipcRenderer.invoke('tab-view-resize', { tabId, bounds }),
    destroy: (tabId: string) => ipcRenderer.invoke('tab-view-destroy', tabId),
    requestClose: (tabId: string) => ipcRenderer.invoke('tab-view-request-close', tabId),
    findExistingConnection: (ip: string, port: number) =>
      ipcRenderer.invoke('tab-view-find-existing-connection', { ip, port })
  },
  ipc: {
    send: (channel: string, ...args: any[]) => ipcRenderer.send(channel, ...args),
    invoke: (channel: string, ...args: any[]) => ipcRenderer.invoke(channel, ...args),
    on: (channel: string, callback: IpcCallback) => registerIpcListener(channel, callback),
    once: (channel: string, callback: IpcCallback) => {
      ipcRenderer.once(channel, (_event: IpcRendererEvent, ...args: any[]) => {
        callback(...args);
      });
    },
    removeAllListeners: (channel: string) => ipcRenderer.removeAllListeners(channel)
  },
  app: {
    onWillQuit: (callback: () => void) => {
      ipcRenderer.on('app-will-quit', () => {
        callback();
      });
    }
  },
  dialog: {
    showEditConnection: (connectionData: { id: string; ip: string; port: number; label: string }) =>
      ipcRenderer.invoke('dialog-show-edit-connection', connectionData),
    showDeleteConnection: (connectionData: {
      id: string;
      ip: string;
      port: number;
      label: string;
    }) => ipcRenderer.invoke('dialog-show-delete-connection', connectionData),
    showTrustedSitesList: () => ipcRenderer.invoke('dialog-show-trusted-sites-list'),
    showHelp: () => ipcRenderer.invoke('dialog-show-help'),
    askTrustSite: (payload: {
      ip: string;
      texts?: {
        title?: string;
        message?: string;
        detail?: string;
        buttons?: string[];
      };
    }) => ipcRenderer.invoke('dialog-ask-trust-site', payload),
    isTrustedSite: (ip: string) => ipcRenderer.invoke('is-trusted-site', { ip }),
    addTrustedSite: (ip: string) => ipcRenderer.invoke('add-trusted-site', { ip }),
    getTrustedSitesList: () => ipcRenderer.invoke('get-trusted-sites-list'),
    updateTrustedSite: (id: string, ip: string) =>
      ipcRenderer.invoke('update-trusted-site', { id, ip }),
    deleteTrustedSite: (id: string, ip: string) =>
      ipcRenderer.invoke('delete-trusted-site', { id, ip })
  }
};

// Use `contextBridge` APIs to expose Electron APIs to
// renderer only if context isolation is enabled, otherwise
// just add to the DOM global.
if (process.contextIsolated) {
  try {
    contextBridge.exposeInMainWorld('electron', electronAPI);
    contextBridge.exposeInMainWorld('api', api);
  } catch (error) {
    console.error(error);
  }
} else {
  // @ts-ignore (define in dts)
  window.electron = electronAPI;
  // @ts-ignore (define in dts)
  window.api = api;
}
